/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package elaborate.tag_analysis.client.ui;

import elaborate.tag_analysis.client.ServiceContext;
import elaborate.tag_analysis.client.ui.model.ResourceTreeNode;
import elaborate.tag_analysis.client.utils.resource_logs.ResourceStatus;
import elaborate.task.Task;
import java.awt.Color;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultTreeCellRenderer;

/**
 *
 * @author lendle
 */
public class ResourceTreeRenderer extends DefaultTreeCellRenderer {

    private ImageIcon iconWithTags = null, iconUnknown = null, iconNoTags = null;
    private List<StatusVerifyingEntry> statusVerifyingQueue = new ArrayList<StatusVerifyingEntry>();
    private boolean redrawNeeded = false;
    private TreeRedrawThread treeRedrawThread = null;
    private ServiceContext serviceContext = null;

    public ServiceContext getServiceContext() {
        return serviceContext;
    }

    public void setServiceContext(ServiceContext serviceContext) {
        this.serviceContext = serviceContext;
    }

    public ResourceTreeRenderer() {
        iconWithTags = new ImageIcon(this.getClass().getClassLoader().getResource("approve_16.gif"));
        iconUnknown = new ImageIcon(this.getClass().getClassLoader().getResource("help16.gif"));
        iconNoTags = new ImageIcon(this.getClass().getClassLoader().getResource("closeAllWindows16.gif"));
        StatusVerifyingThread t = new StatusVerifyingThread();
        t.start();
        treeRedrawThread = new TreeRedrawThread();
        treeRedrawThread.start();
    }

    @Override
    public Component getTreeCellRendererComponent(JTree jtree, Object o, boolean bln, boolean bln1, boolean bln2, int i, boolean hasFocus) {
        treeRedrawThread.setTree(jtree);
        JLabel label = (JLabel) super.getTreeCellRendererComponent(jtree, o, bln, bln1, bln2, i, hasFocus);
        ResourceTreeNode treeNode = (ResourceTreeNode) o;
        if (treeNode.isCategory()) {
            try {
                //for category node, use color to represent status
                if (!this.serviceContext.getActiveApplication().getResourceHandler().isCategoryStatusVerified(treeNode)) {
                    label.setForeground(Color.RED);
                }
            } catch (Exception ex) {
                Logger.getLogger(ResourceTreeRenderer.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            //for resource node, use icon to represent status
            if (treeNode != jtree.getModel().getRoot()) {
                label.setIcon(this.iconUnknown);
            }
            //once checked, will not contact server for status again unless reload is fired (not implemented now)
            if (treeNode.isStatusChecked() == false && treeNode.isCategory() == false && treeNode.getStatus() == ResourceTreeNode.STATUS_UNKNOWN && treeNode.getResource() != null) {
                treeNode.setStatusChecked(true);//once checked, will not contact server for status again unless reload is fired (not implemented now)
                this.addStatusVerifyingEntry(new StatusVerifyingEntry(jtree, treeNode));
            }
            if (treeNode.getStatus() == ResourceTreeNode.STATUS_NO_TAGS) {
                label.setIcon(this.iconNoTags);
            } else if (treeNode.getStatus() == ResourceTreeNode.STATUS_TAGS) {
                label.setIcon(this.iconWithTags);
            }
        }

        return label;
    }

    protected synchronized void addStatusVerifyingEntry(StatusVerifyingEntry entry) {
        redrawNeeded = true;
        this.statusVerifyingQueue.add(entry);
        this.notifyAll();
    }

    protected synchronized StatusVerifyingEntry getStatusVerifyingEntry() {
        while (this.statusVerifyingQueue.isEmpty()) {
            try {
                this.wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(ResourceTreeRenderer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return this.statusVerifyingQueue.remove(0);
    }

    class StatusVerifyingThread extends Thread {

        private ExecutorService executorService = null;

        public StatusVerifyingThread() {
            this.setDaemon(true);
            //use 10 concurrent threads for verifying status
            executorService = Executors.newFixedThreadPool(10);
        }

        public void run() {
            while (true) {
                try {
                    final StatusVerifyingEntry entry = getStatusVerifyingEntry();

                    serviceContext.executeTask(new Task() {

                        @Override
                        public Object run() throws Exception {
                            executorService.execute(new Runnable() {

                                @Override
                                public void run() {
                                    try {
                                        ResourceTreeNode treeNode = entry.getTreeNode();

                                        //String key=treeNode.getResource().getApplicationId()+"::"+treeNode.getResource().getId();

                                        ResourceStatus status = serviceContext.getActiveApplication().getResourceHandler().getResourceStatus(treeNode);
                                        if (treeNode.getStatus() != ResourceTreeNode.STATUS_UNKNOWN) {
                                            //no effect if the treeNode status is known
                                            //this is possible because of preemption in
                                            //TaskQueue
                                            return;
                                        }
                                        if (status.equals(ResourceStatus.UNKNOWN)) {
                                            treeNode.setStatus(ResourceTreeNode.STATUS_UNKNOWN);
                                        } else if (status.equals(ResourceStatus.WITHTAGS)) {
                                            treeNode.setStatus(ResourceTreeNode.STATUS_TAGS);
                                        } else if (status.equals(ResourceStatus.NODATA)) {
                                            treeNode.setStatus(ResourceTreeNode.STATUS_NO_TAGS);
                                        }
                                    } catch (Exception ex) {
                                        Logger.getLogger(ResourceTreeRenderer.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                                }
                            });

                            return null;
                        }
                    });

                } catch (Exception e) {
                }
            }
        }
    }

    class TreeRedrawThread extends Thread {

        protected JTree tree;

        /**
         * Get the value of tree
         *
         * @return the value of tree
         */
        public JTree getTree() {
            return tree;
        }

        /**
         * Set the value of tree
         *
         * @param tree new value of tree
         */
        public void setTree(JTree tree) {
            this.tree = tree;
        }

        public TreeRedrawThread() {
            this.setDaemon(true);
        }

        public void run() {
            while (true) {
                try {
                    Thread.sleep(5000);
                    if (tree != null && redrawNeeded) {
                        SwingUtilities.invokeLater(new Runnable() {

                            @Override
                            public void run() {
                                tree.repaint();
                            }
                        });
                        redrawNeeded = false;
                    }
                } catch (Exception e) {
                }
            }
        }
    }

    class StatusVerifyingEntry {

        protected JTree tree;
        protected ResourceTreeNode treeNode;

        public StatusVerifyingEntry(JTree tree, ResourceTreeNode treeNode) {
            this.tree = tree;
            this.treeNode = treeNode;
        }

        /**
         * Get the value of treeNode
         *
         * @return the value of treeNode
         */
        public ResourceTreeNode getTreeNode() {
            return treeNode;
        }

        /**
         * Set the value of treeNode
         *
         * @param treeNode new value of treeNode
         */
        public void setTreeNode(ResourceTreeNode treeNode) {
            this.treeNode = treeNode;
        }

        /**
         * Get the value of tree
         *
         * @return the value of tree
         */
        public JTree getTree() {
            return tree;
        }

        /**
         * Set the value of tree
         *
         * @param tree new value of tree
         */
        public void setTree(JTree tree) {
            this.tree = tree;
        }
    }
}
